/*
    This file is part of QTau
    Copyright (C) 2013-2019  Tobias "Tomoko" Platen <tplaten@posteo.de>
    Copyright (C) 2013       digited       <https://github.com/digited>
    Copyright (C) 2010-2013  HAL@ShurabaP  <https://github.com/haruneko>

    QTau is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    SPDX-License-Identifier: GPL-3.0+
*/

// FIXME upgrade to mbrola 3 synth (festvox sucks)

#include "festvox_synth.h"
#include "../editor/ustjkeys.h"
#include "QFile"
#include "QTextStream"

#define __devloglevel__ 4

QString FestvoxSynth::name()        { return "FestVox"; }
QString FestvoxSynth::description() { return "Daisy Bell - IBM 7094"; }
QString FestvoxSynth::version()     { return "19.04"; }
bool FestvoxSynth::synthIsRealtime() { return false; }

void __devlog__(QString logtype,QString filename,int line,QString msg)
{
    QString logmsg = logtype+": "+filename.replace("../../","").replace("../","")+":"+QVariant(line).toString()+": "+msg;
    fprintf(stderr,"[synth]%s\n",logmsg.toUtf8().data());
}

class FestvoxScore
{
    QString xml;
public:
    FestvoxScore()
    {
        xml = "<SINGING BPM=\"60\">\n";
    }
    void addNote(int noteNum,float length,float rest,QString lyric)
    {
        QString noteNames[] = {"C","C#","D","D#","E","F","F#","G","G#","A","A#","B"};
        int octave = noteNum/12-2;
        int step = noteNum % 12;
        QString pitch = QString("%1%2").arg(noteNames[step]).arg(octave);
        if(rest>0)
            xml += QString("\t<REST BEATS=\"%1\"></REST>\n").arg(rest);
        xml += QString("\t<DURATION BEATS=\"%1\"><PITCH NOTE=\"%2\">%3</PITCH></DURATION>\n").arg(length).arg(pitch).arg(lyric);
    }
    QString getScore()
    {
        xml += "</SINGING>\n";
        return xml;
    }

};

void FestvoxSynth::setup(IController* ctrl)      {
    this->_ctrl = ctrl;
    this->_jack_samplerate = ctrl->sampleRate();

    connect(this,&FestvoxSynth::logDebug,this,&FestvoxSynth::on_logDebug);
    connect(this,&FestvoxSynth::logError,this,&FestvoxSynth::on_logError);
    connect(this,&FestvoxSynth::logSuccess,this,&FestvoxSynth::on_logSuccess);
    connect(this,&FestvoxSynth::endOfThread,this,&FestvoxSynth::on_endOfThread);
}



bool FestvoxSynth::synthesize(IScore* score)
{
    FestvoxScore fvox;
    DEVLOG_DEBUG("FestvoxSynth::synthesize");
    for(int i=0;i<score->getNoteCount();i++)
    {
        auto n = score->getNote(i);
        DEVLOG_DEBUG("note "+STR(i));
        DEVLOG_DEBUG("rest "+STR(n.rest)+" length "+STR(n.lenght));
        fvox.addNote(n.pitch,n.lenght,n.rest,n.lyric);
    }
    QFile file("/tmp/festvox.xml");
    file.open(QIODevice::WriteOnly | QIODevice::Text);
    QTextStream out(&file);
    out << fvox.getScore();
    file.close();
    return false;
    /// return true; //will be scheduled if true


}

void FestvoxSynth::synthThread()
{
    SF_INFO info;
    memset(&info,0,sizeof(info));
    info.format =  SF_FORMAT_WAV | SF_FORMAT_PCM_16;
    info.samplerate = _jack_samplerate;
    info.channels = 1;
    SNDFILE* sndfile = sf_open("/tmp/festvox_synth.wav",SFM_WRITE,&info);

    int data_count = 1024;
    float* data = new float[data_count];

    while(1)
    {
        int result = readData(data,data_count);
        if(result) break;
        sf_write_float(sndfile,data,data_count);
    }

    sf_close(sndfile);
    delete[] data;
    emit endOfThread();

}


int FestvoxSynth::readData(float *data, int size)
{
    (void)data;
    (void)size;
    //FIXME
    abort();
}



void FestvoxSynth::buildScore()
{

}

QString FestvoxSynth::getTranscription(QString txt)
{
    return txt;
}

bool FestvoxSynth::doPhonemeTransformation(QStringList& list)
{
    (void) list;
    return false;
}

bool FestvoxSynth::setVoice(QString voiceName)
{
   if(voiceName=="(voice_kal_diphone)") return true;
   return false;
}

QStringList FestvoxSynth::listVoices()
{
   QStringList voices;
   voices << "(voice_kal_diphone)";
   return voices;
}

//??
void FestvoxSynth::on_logError(QString error)
{
    _ctrl->logError(error);
}

void FestvoxSynth::on_logSuccess(QString success)
{
    _ctrl->logSuccess(success);
}

void FestvoxSynth::on_logDebug(QString debug)
{
    _ctrl->logDebug(debug);
}

void FestvoxSynth::on_endOfThread()
{
    //_threadRunning = false;
    //_ctrl->startOfflinePlayback("/tmp/festvox_synth.wav");
}

bool FestvoxSynth::setCacheDir(QString cacheDir)
{
    (void) cacheDir;
    return true;
}
